home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1996 #15 / Monster Media Number 15 (Monster Media)(July 1996).ISO / prog_c / kbstf10.zip / KBSTUFFR.C < prev    next >
Text File  |  1996-01-31  |  18KB  |  454 lines

  1. #ifndef __TINY__
  2. #error Must be compiled in tiny model
  3. #endif
  4.  
  5. #define NULL 0
  6. #if __STDC__
  7. #define _Cdecl
  8. #else
  9. #define _Cdecl cdecl
  10. #endif
  11.  
  12. void _Cdecl __cli__ (void);
  13. void _Cdecl __sti__ (void);
  14. void _Cdecl __int__(int interruptnum);
  15. /* extern unsigned _Cdecl _psp; */
  16.  
  17.  
  18. /* *********************************************************************** */
  19. /*   The little assembly TSR KBSTFRES.COM hooks INT 1Ch (user interrupt),  */
  20. /*  complying with IBM's INTERRUPT-SHARING PROTOCOL and  stuffs the  key-  */
  21. /*  board buffer with the 2-bytes words it finds in his internal buffer.   */
  22. /*   This 2-bytes words are in general formed by the ASCII translation in  */
  23. /*  the low byte and the scan code in the high byte.  Extended characters  */
  24. /*  could have an ASCII translation of 0 or E0  (for the extended 101/102  */
  25. /*  keys keyboards) or F0 (other extended chars).   You  can inspect keys  */
  26. /*  stored in the keyboard buffer from the standard  INT 9h handler  with  */
  27. /*  the program SEEKBBUF.COM (with Turbo-c source).                        */
  28. /*   A word with value 0 shouldn't never be generated by standard  INT 9h  */
  29. /*  handler and so the TSR interprets a 0 in his buffer as a request of a  */
  30. /*  pause, and the following word represent for it the number  of  clock-  */
  31. /*  ticks to wait.  A 0 as number of ticks is interpreted as 65536.        */
  32. /*   Even a word with the high byte equals to 0xFF should never be  gene-  */
  33. /*  rated by the standard INT 9h handler and so the TSR  interprets  this  */
  34. /*  as a "short pause", the low byte representing the number of thicks, 0  */
  35. /*  interpreted again as 65536.                                            */
  36. /*   The KBSTFRES.COM's buffer is a circular buffer similarly to the key-  */
  37. /*  board buffer, but it's bigger and could be made even bigger,  alloca-  */
  38. /*  ting memory, even if the TSR is already installed.                     */
  39. /*   The KBSTFRES.COM's companion program KBSTUFFR.COM is  used  to store  */
  40. /*  keys in the TSR's buffer.  It could be even used as a scheme for  ad-  */
  41. /*  ding other options as allocating another buffer.                       */
  42. /*                                                                         */
  43. /*   The way to use KBSTUFFR is simple for c programmers.                  */
  44. /*   syntax:                                                               */
  45. /*   KBSTUFFR [/R] [/U] [/G] [/S] <what to stuff>                          */
  46. /*     /R          Option. If present must be the first parameter, other-  */
  47. /*                wise is interpreted as two characters to store.          */
  48. /*                 Reset the TSR's buffer.                                 */
  49. /*     /U          Option. If present must be the first parameter, other-  */
  50. /*                wise is interpreted as two characters to store.          */
  51. /*                 Whatever follow this option is obviously ignored.       */
  52. /*                 Uninstall the TSR and remove it from memory.            */
  53. /*          /R and /U options are mutually excluding.    Both must be the  */
  54. /*          first option. The use of both is, however, a nonsense.         */
  55. /*     /S          Stops the TSR.     |_   Can appear anywhere outside of  */
  56. /*     /G          Restarts the TSR.  |   C-strings                        */
  57. /*     <what to stuff> are the characters to store in the buffer.          */
  58. /*                 Blanks and tabs are generally skipped, but you can use  */
  59. /*                a C-type string, as, for example,                        */
  60. /*                  "pippo a:\r"                                           */
  61. /*                  "\r\n\t\aError in C:\\work\r\n"                        */
  62. /*                  "\76\xFDThis are octal and hexadecimal notation\?"     */
  63. /*                 \OOO and \xHHH are accepted as for ANSI C, but if  the  */
  64. /*                value of FFh is exceeded only the low byte is  conside-  */
  65. /*                red and the high is stripped.                            */
  66. /*                 With this "normal" use only ASCII translation are sto-  */
  67. /*                red, without scan code, as the keys would have been ge-  */
  68. /*                nerated with the ALT-key+Keypad numbers combination.     */
  69. /*                 My extensions to C-string allow to store extended keys  */
  70. /*                with a low byte of 0 and special pause sequences.        */
  71. /*                 To store the word 6800h, for example, many methods can  */
  72. /*                be used:                                                 */
  73. /*                  "\0\x68","\ex68" (where the escape sequence \e is  an  */
  74. /*                  extension to the standard C-string syntax), "\0h"  or  */
  75. /*                  "\eh" (where ascii('h')=0x68)                          */
  76. /*                 The x is used as an escape character for the \e escape  */
  77. /*                sequence, so if 7800h(=<ALT 1>) has to be stored can be  */
  78. /*                used:                                                    */
  79. /*                  "\ex78","\0\x78","\0x" or "\exx"                       */
  80. /*                 To store a pause, the other extension "\pDDDDD" has to  */
  81. /*                be used where DDDDD is a decimal number.   If only "\p"  */
  82. /*                or "\p0" is entered the pause is set to the default  of  */
  83. /*                1 clock-tick.                                            */
  84. /*                                                                         */
  85. /*   Thanks a lot to Chris Dunford  for  posting informations about IBM's  */
  86. /*  INTERRUPT-SHARING PROTOCOL                                             */
  87. /*                                                                         */
  88. /*                                                                         */
  89. /*   (c) 1996 by Luigi Mancinelli                                          */
  90. /*   manci@alpha.science.unitn.it                                          */
  91. /*                                                                         */
  92. /*   Note: If the program has to be recompiled, the tiny model has  to be  */
  93. /*  used and the resulting .exe has to be converted in .com (with the DOS  */
  94. /*  utility EXE2BIN for example) or the program doesn't work.              */
  95. /*                                                                         */
  96. /* *********************************************************************** */
  97.  
  98. #define MK_FP(seg,ofs)  ((void far *) \
  99.                            (((unsigned long)(seg) << 16) | (unsigned)(ofs)))
  100. #define SET_FP_OFF(fp,ofs)  ((void far *) \
  101.                       ((((unsigned long)(fp))&0xFFFF0000)|(unsigned)(ofs)))
  102. #define FAR_BYTE(fp) (*((unsigned char far *) (fp)))
  103. #define FAR_ULONG(fp) (*((unsigned long far *) (fp)))
  104.  
  105. #define _toupper(c)     ((c)&0xDF)
  106.  
  107. #define putchar(c) (_DL=c,_AH=02,__int__(0x21))
  108.  
  109. #define putbackslash() (_DL='\\',_AH=02,__int__(0x21))
  110.  
  111. void putstring(char *p)
  112. {   unsigned int i=0;
  113.     if (p!=NULL)
  114.        while (p[i]!=0) putchar(p[i++]);
  115. }
  116.  
  117.   char *HexDig="0123456789ABCDEF";
  118.  
  119. void puthexbyte(unsigned char ch)
  120. {
  121.    putchar(HexDig[ch>>4]);
  122.    putchar(HexDig[ch&0xF]);
  123. }
  124.  
  125. void puthexword(unsigned int w)
  126. {
  127.    puthexbyte( ((unsigned char *) &w)[1] );
  128.    puthexbyte( *((unsigned char *) &w) );
  129. }
  130.  
  131. void putpntr(void far *p)
  132. {
  133.    puthexword( ((unsigned int *) &p)[1] );
  134.    putchar(':');
  135.    puthexword( *((unsigned int *) &p) );
  136. }
  137.  
  138. void newline(void)
  139. {  putchar('\r'); putchar('\n'); }
  140.  
  141. int IsGoodSeparator(unsigned char Ch)
  142. { return (Ch==0x0D)||(Ch==' ')||(Ch==9)||(Ch=='"'); }
  143.  
  144. typedef struct TSRPROTSTRU {
  145.     unsigned int ShortJmp;
  146.     struct TSRPROTSTRU far * Old;
  147.     unsigned int Signature;
  148.     char flag;
  149.     unsigned int ShortJmpHWreset;
  150.     char bytes[7];
  151.     unsigned int MyJump;
  152.     char recognise[5];
  153.     char retf;
  154.     unsigned int bufseg;
  155.     unsigned int bufstart;
  156.     unsigned int bufend;
  157.     unsigned int bufhead;
  158.     unsigned int buftail;
  159.     unsigned char IsActive;
  160.     unsigned char IsInError;
  161.     unsigned char IsInPause;
  162.     unsigned char IsStopped;
  163.     }  TsrProtStructure;
  164.  
  165. typedef TsrProtStructure far *TsrProt;
  166.  
  167.  
  168. TsrProt GetVect(unsigned char i)
  169. {
  170.     
  171.     _AH=0x35; _AL=i; /* _AX=0x3500 | i; */
  172.     __int__(0x21);
  173.     return (TsrProt) MK_FP(_ES,_BX);
  174. }
  175.  
  176. void SetVect(unsigned char i, TsrProt P)
  177. {
  178.     unsigned int SaveDS;
  179.     SaveDS=_DS;
  180.     _DX=*((unsigned int *)(&P));
  181.     _DS=((unsigned int *)(&P))[1];
  182.     _AL=i; _AH=0x25;   /* _AX=0x2500 | i; */
  183.     __int__(0x21);
  184.     _DS=SaveDS;
  185.     return;
  186. }
  187.  
  188. #define SEG_OF_FARP(FP) (((unsigned int *)(&(FP)))[1])
  189. #define FreeDOSMem(SEG) (_ES=SEG,_AH=0x49,__int__(0x21))
  190.  
  191. int IsCorrectTsrProtStru(TsrProt P)
  192. {
  193.  
  194.     if (P==NULL) return 0;
  195.     else if (P->Signature!=0x424B) return 0;
  196.     /* comment following line for a less strict control */
  197.     else if (P->ShortJmp!=0x10EB) return 0;
  198.     else return 1;
  199. }
  200.  
  201. int IsKBSTFRES(TsrProt P)
  202. {
  203.     if (IsCorrectTsrProtStru(P)==0) return -1;
  204.     else if ((P->recognise[0]=='K')&&(P->recognise[1]=='B')&&
  205.              (P->recognise[2]=='S')&&(P->recognise[3]=='T')&&
  206.              (P->recognise[4]=='F') ) return 1;
  207.     else return 0;
  208. }
  209.  
  210. TsrProt Pntr;
  211. TsrProt OldPntr=NULL;
  212.  
  213. #define FULL 1
  214. #define STRING 2
  215. #define EXTCHAR 4
  216. #define PAUSE 8
  217. #define SWITCHFOUND 128
  218.  
  219.   unsigned int p,n;
  220.   unsigned int far * FarP;
  221.   unsigned char Ch,c;
  222.   unsigned int Word;
  223.   unsigned long int Ticks;
  224.   char Flags=0;
  225.  
  226.   char *ToNewPtr=" => ";
  227.   char *Mess="Stuffed ...\"";
  228.   char *CheckMess="Actual int 1Ch handler => ";
  229.   char *ErrMess="Cannot inspect TSR chain - KBSTFRES not found\r\n";
  230.   char *Going="OK";
  231.   char *Stopped="STOPPED";
  232.   char *TryUnInst="Attempting to uninstalling KBSTFRES\r\n";
  233.   char *Win="In DOS Windows  ";
  234.   char *NotUnInWin="Unable to uninstall from a DOS Windows\r\n";
  235.   char *Uninstalled="KBSTFRES successfully uninstalled\r\n";
  236.   char *Re_Chaining="Re-chaining to old interrupt ";
  237.   char *Restoring="Restoring old interrupt ";
  238.  
  239. /* *************************** */
  240. unsigned char *CmdStr=(unsigned char *) 0x80;
  241. int i=1;
  242.  
  243. void SkipBlanks(void) {
  244.    while ((CmdStr[i]==' ')||(CmdStr[i]==9)) i++;
  245. }
  246.  
  247. /* *************************** */
  248. int GetHexByte(void)
  249. {
  250.    /* register c; */
  251.    unsigned int j=0;
  252.    Ch=0;
  253.    while((j++<3)&&
  254.          ( (((c=CmdStr[i])>='0')&&(c<='9')) ||
  255.            (((c=_toupper(c))>='A')&&(c<='F')) ) )  {
  256.       if(c>='A') c-=('A'-10); else c-='0';
  257.       Ch=(Ch<<4)+c; i++;
  258.    }
  259. }
  260.  
  261. main() {
  262. /*
  263. unsigned int DS=((unsigned long)((char far *)(&CmdStr)))>>16;
  264. if(DS==_psp) { */
  265.    int Fnd;
  266.  
  267.    /* now try to find KBSTFRES as int 1Ch handler */
  268.    Pntr=/* (TsrProt) getvect(0x1C) */ GetVect(0x1C);
  269.    putstring(CheckMess);   putpntr(Pntr);   newline();
  270.    if( (((unsigned int)(Pntr))==0x98)&&
  271.        (FAR_BYTE(SET_FP_OFF(Pntr,0xB7))==0x2E) &&
  272.        (FAR_ULONG(SET_FP_OFF(Pntr,0xB8))==0x00942EFF) ) {
  273.       /* is DOS Windows ? */
  274.       putstring(Win);
  275.       OldPntr=Pntr;    Pntr=*((TsrProt far *)SET_FP_OFF(OldPntr,0x0094));
  276.       putpntr(OldPntr); putstring(ToNewPtr); putpntr(Pntr);    newline();
  277.       OldPntr=(TsrProt) 0xFFFFFFFF;
  278.    }
  279.  
  280.    while ((Fnd=IsKBSTFRES(Pntr))==0) {
  281.       OldPntr=Pntr;  Pntr=Pntr->Old;
  282.       putpntr(OldPntr); putstring(ToNewPtr); putpntr(Pntr); newline();
  283.    }
  284.    if(Fnd==-1) {
  285.       putstring(ErrMess);
  286.       return 1;
  287.    }
  288.    else {
  289.       (Pntr->IsActive)++;
  290.       while (Pntr->IsActive>1) /* wait exit from 1Ch handler */
  291.          { putchar(Pntr->IsActive+48);  putchar('\r');  }
  292.  
  293.       ((unsigned int *)(&FarP))[1]=Pntr->bufseg;
  294.       p=CmdStr[0];  if(CmdStr[p+1]!=0x0D) CmdStr[p+1]=0x0D;
  295.       SkipBlanks();
  296.       if((CmdStr[i]=='/')&&
  297.          ((_toupper(CmdStr[i+1])=='U')||(_toupper(CmdStr[i+1])=='R'))&&
  298.          (IsGoodSeparator(CmdStr[i+2])) ) {
  299.          if (_toupper(CmdStr[i+1])=='U') {
  300.             if (((unsigned long) OldPntr)==0xFFFFFFFF) {
  301.                Pntr->IsStopped=1;
  302.                Pntr->bufhead=Pntr->buftail=Pntr->bufstart;
  303.                Pntr->IsInPause=0;
  304.                (Pntr->IsActive)--;
  305.                putstring(NotUnInWin);
  306.                return 2;     
  307.             }
  308.             else {
  309.                /* now try to unhook int 1Ch */
  310.                putstring(TryUnInst);
  311.                if (OldPntr!=NULL) { /* adjust the after loaded TSR */
  312.                   putstring(Re_Chaining);
  313.                   __cli__();
  314.                   OldPntr->Old=Pntr->Old;
  315.                   __sti__();
  316.                }
  317.                else {
  318.                   putstring(Restoring);
  319.                   SetVect(0x1C,Pntr->Old);
  320.                }
  321.                putpntr(Pntr->Old); newline();
  322.                FreeDOSMem(SEG_OF_FARP(Pntr));
  323.                putstring(Uninstalled);
  324.                return 0;     
  325.             }
  326.          }
  327.          else {
  328.             Pntr->bufhead=Pntr->buftail=Pntr->bufstart;
  329.             Pntr->IsInPause=0;
  330.             i+=2; SkipBlanks();
  331.          }
  332.       }
  333.  
  334.       putstring(Mess);
  335.            /* printf("Stuffed...\""); */
  336.       while (((Ch=CmdStr[i++])!=0x0D)&&((Flags & FULL)==0)) {
  337.          if((Ch=='"')&&(Flags & STRING)) Flags&=~STRING & ~EXTCHAR;
  338.          else {
  339.             if(Ch=='"') {
  340.                register j=i;      Ch=CmdStr[i++];
  341.                while ((CmdStr[j]!=0x0D)&&
  342.                       ((CmdStr[j]!='"')||(CmdStr[j-1]=='\\'))) j++;
  343.                if(CmdStr[j]==0x0D) break; else Flags|=STRING;
  344.             }
  345.             if((Flags & STRING)&&(Ch=='\\')) {
  346.                if(((Ch=CmdStr[i++])>='0')&&(Ch<='7')) {
  347.                   register j=1; /* register c; */
  348.                   Ch-='0';
  349.                   while((j++<3)&&(((c=CmdStr[i])>='0')&&(c<='7')) )
  350.                      { Ch=(Ch<<3)+(c-'0'); i++; }
  351.                }
  352.                else switch (Ch) {
  353.                /* My extensions to normal C string syntax */
  354.                case 'p':{
  355.                          register c;  register unsigned int j=0;
  356.                          Ch='p';  Ticks=0;
  357.                          while((j++<5)&&
  358.                                (((c=CmdStr[i])>='0')&&(c<='9')) )
  359.                            { Ticks=(Ticks<<3)+(Ticks<<1)+(c-'0'); i++; }
  360.                         }
  361.                         if(Ticks>65536) Ticks=65536;
  362.                         else if(Ticks==0) Ticks=1;
  363.                         Flags|=PAUSE;
  364.                         break;
  365.                case 'e':Ch=0;
  366.                         if(CmdStr[i]=='x') {
  367.                           Flags|=EXTCHAR;
  368.                           if(CmdStr[++i]=='x') { Ch='x'; i++; }
  369.                           else GetHexByte();
  370.                         }
  371.                         break;
  372.                /* normal C string syntax */
  373.                case 'a':Ch=7; break;
  374.                case 'b':Ch=8; break;
  375.                case 'f':Ch=0x0C; break;
  376.                case 'n':Ch=0x0A; break;
  377.                case 'r':Ch=0x0D; break;
  378.                case 't':Ch=0x09; break;
  379.                case 'v':Ch=0x0B; break;
  380.                case 'X':
  381.                case 'x':GetHexByte();
  382.                         break;
  383.                case '\'':
  384.                case '\?':
  385.                case '"':
  386.                case '\\':break;
  387.                }
  388.             }
  389.             else if(Ch=='/')
  390.                switch (_toupper(CmdStr[i])) {
  391.                case 'S':
  392.                case 'G':if(IsGoodSeparator(CmdStr[i+1])) {
  393.                            Pntr->IsStopped=(CmdStr[i++]=='S');
  394.                            Flags|=SWITCHFOUND;
  395.                            SkipBlanks();
  396.                         }
  397.                         break;
  398.                }
  399.             if (Flags & SWITCHFOUND) Flags&=~SWITCHFOUND;
  400.             else if(Ch==0) Flags|=EXTCHAR;
  401.             else {
  402.                if((n=p=Pntr->buftail+2)==Pntr->bufend) p=Pntr->bufstart;
  403.                if(Flags & PAUSE) {
  404.                   if((n+=2)==Pntr->bufend) n=Pntr->bufstart;
  405.                }
  406.                if((p!=Pntr->bufhead)&&(n!=Pntr->bufhead)) {
  407.                   if(Flags & PAUSE) {
  408.                      register unsigned int j=10000;
  409.                      Word=Ticks;  Flags&=~PAUSE;
  410.                      putbackslash(); putchar('p');
  411.                      while ((Ch=(Ticks/j))==0) j/=10;
  412.                      putchar(Ch+'0'); Ticks-=Ch*j;
  413.                      while (j>1) {
  414.                         putchar((Ch=Ticks/j)+'0');
  415.                         Ticks-=Ch*j; j/=10;
  416.                      }
  417.                      if (Word<256) Word|=0xFF00;
  418.                      else {
  419.                         *((unsigned int *)(&FarP))= Pntr->buftail;
  420.                         (*FarP)=0;  Pntr->buftail=p;  p=n;
  421.                      }
  422.                   }
  423.                   else {
  424.                      if(Flags & EXTCHAR) {
  425.                         Word=((unsigned int) Ch)<<8;
  426.                         putbackslash();  putchar('e');
  427.                         if(Ch=='x') putchar('x');
  428.                      }
  429.                      else Word=Ch & 0xFF;
  430.                      if(Ch=='\\') putbackslash();
  431.                      else if((Ch>=32)&&(Ch!=127)&&(Ch!=255)) putchar(Ch);
  432.                      else {
  433.                         if((Flags & EXTCHAR)==0) putbackslash();
  434.                         putchar('x');
  435.                         puthexbyte(Ch);
  436.                      }
  437.                   }
  438.                   *((unsigned int *)(&FarP))= Pntr->buftail;
  439.                   (*FarP)=Word;
  440.                   Pntr->buftail=p;
  441.                } else Flags|=FULL;
  442.                Flags&=~EXTCHAR;
  443.             }
  444.          }
  445.          if ((Flags & STRING)==0) SkipBlanks();
  446.       }
  447.       putchar('"'); newline();
  448.  
  449.       if(Pntr->IsStopped) putstring(Stopped); else putstring(Going);
  450.       newline();
  451.       (Pntr->IsActive)--;
  452.    }
  453. /* } */
  454. }